/*
题目: LRU缓存
请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类：

    LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
    int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。
    void put(int key, int value) 如果关键字 key 已经存在，则变更其数据值 value ；如果不存在，则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ，则应该 逐出 最久未使用的关键字。

函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
https://leetcode.cn/problems/lru-cache
 */
public class LRUCache {
    //哈希-双向链表
    Map<Integer, Node> map = new HashMap<> ();

    Node head = null; //头部放的是用的少的, 尾巴放的是用的多的
    Node last = null;
    public class Node {
        Node prev;
        Node next;
        int val;
        int key;

        public Node(int val, int key) {
            this.val = val;
            this.key = key;
        }
    }

    private void adjust(Node cur) {
        if (cur == head) {
            if (head.next == null) {  //只有一个元素
                return;
            }
            head = head.next;
            head.prev = null;
            cur.next = null;
            cur.prev = last;
            last.next = cur;
            last = cur;
            return;
        } else if (cur == last) {
            return;
        }
        cur.prev.next = cur.next;
        cur.next.prev = cur.prev;
        last.next = cur;
        cur.prev = last;
        cur.next = null;
        last = cur;
    }

    private void add(Node newNode) {
        if (last == null) { //如果没有元素, 这个节点就是头尾结点
            head = last = newNode;
            return;
        }
        last.next = newNode;  //新加进来的放在尾巴节点后面
        newNode.prev = last;
        last = newNode;
    }

    int capacity = 0;
    int size = 0;
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }

    public int get(int key) {
        if (!map.containsKey(key)) {
            return -1;
        }
        Node cur = map.get(key);
        adjust(cur);
        return cur.val;
    }

    public void put(int key, int value) {
        if (map.containsKey(key)) {
            Node cur = map.get(key);
            cur.val = value;
            adjust(cur);
            return;
        }
        Node newNode = new Node(value, key);
        map.put(key, newNode);
        add(newNode);
        if (size == capacity) {
            map.remove(head.key);
            head = head.next;
            head.prev = null;
        } else {
            size++;
        }
    }
}
